# Fichier: python_cheats/cheatsheets/reseaux_pour_developpeur.txt
# Cheatsheet Réseaux pour Développeur Python - Guide Ultra-Détaillé pour Grands Débutants

[OK] CONCEPTS FONDAMENTAUX (EXPLICATIONS TRÈS DÉTAILLÉES)

# === QU'EST-CE QUE LES RÉSEAUX? ===

# POURQUOI LES RÉSEAUX?
# ========================
# Imagine tu crées un jeu vidéo sur ton ordinateur
# En ce moment:
#   - Le jeu lit les fichiers sur ton disque dur
#   - Le jeu affiche les images sur ton écran
#   - Le jeu écoute ton clavier/souris
# Tout fonctionne parfaitement... mais seulement TU peux y jouer!

# Problème: Comment faire pour que d'AUTRES joueurs jouent avec toi?
# Ils ont leurs ordinateurs chez eux, très loin de toi!
# Comment envoyer des données entre vos ordinateurs?

# RÉPONSE: Les réseaux informatiques!
# = Un système de communication entre ordinateurs
# = Chaque ordinateur peut envoyer et recevoir des données

# Analogie: Les réseaux = La poste
#   - Chaque maison = un ordinateur
#   - La poste = Internet (le réseau)
#   - Les lettres = les données
#   - L'adresse postale = adresse IP
#   - Le numéro de porte = numéro de port

# Sans les réseaux: Tu ne peux communiquer qu'avec TOI-MÊME
# Avec les réseaux: Tu peux communiquer avec des milliards d'ordinateurs!


# QUAND UTILISER LES RÉSEAUX?
# ============================
# Voici les situations où tu as BESOIN des réseaux:

# 1. Les utilisateurs sont loin de toi
#    - App web que des gens utilisent d'autres villes/pays
#    - App mobile que les gens téléchargent
#    - Multiplayer game

# 2. Tu as besoin de données d'autres services
#    - Tu veux utiliser Google Maps dans ton app
#    - Tu veux accéder à une base de données sur un serveur
#    - Tu veux envoyer des emails (nécessite un serveur email)

# 3. Tu veux que plusieurs ordinateurs travaillent ensemble
#    - Partager des fichiers entre ordinateurs
#    - Synchroniser des données en temps réel
#    - Avoir plusieurs serveurs pour supporter beaucoup d'utilisateurs


# COMMENT LES RÉSEAUX FONCTIONNENT?
# ==================================
# Procédure simple (très simplifiée):

# 1. Mon ordinateur (Client)
#    └─ "Je veux des données de Google!"

# 2. Internet (Le réseau)
#    └─ Ma requête voyage à travers Internet
#    └─ Passe par plein de routeurs et câbles
#    └─ Arrive à Google

# 3. Serveur Google (Server)
#    └─ "J'ai reçu une requête"
#    └─ Cherche les données demandées
#    └─ Envoie la réponse

# 4. Internet (Le réseau)
#    └─ La réponse voyage vers mon ordinateur
#    └─ Passe par plein de routeurs et câbles
#    └─ Arrive chez moi

# 5. Mon ordinateur (Client)
#    └─ "J'ai reçu les données!"
#    └─ Les affiche sur mon écran

# TEMPS TOTAL: Quelques millisecondes!


# === VOCABULAIRE FONDAMENTAL (TRÈS IMPORTANT!) ===

# IP ADDRESS (Adresse IP)

# POURQUOI?
# =========
# Les ordinateurs sur Internet ont besoin d'adresses uniques
# Sinon, comment saurait-on qui reçoit les données?
# C'est comme les adresses postales: sans adresse, la poste ne sait pas où envoyer

# QUAND?
# ======
# Chaque ordinateur, smartphone, serveur connecté à Internet a une IP
# Si tu fais ping google.com, ta machine demande d'abord l'IP de Google
# Puis elle envoie les données à cette IP

# COMMENT?
# ========
# Format d'une IP: quatre nombres séparés par des points
# Chaque nombre peut aller de 0 à 255
# Exemples:
#   192.168.1.1     = Ton routeur à la maison
#   127.0.0.1       = TON ORDINATEUR (localhost)
#   8.8.8.8         = Serveur DNS de Google
#   142.250.1.101   = Serveur de Google

# Différences principales:
#   127.0.0.1 = C'est TOI, seulement accessible depuis TON ordinateur
#   192.168.x.x = IP locale, accessible sur TON réseau (maison/bureau)
#   8.8.8.8 = IP publique, accessible de partout dans le monde

# IPv4 vs IPv6:
#   IPv4 = 192.168.1.1 (ancien format, 32 bits, ~4 milliards adresses)
#   IPv6 = 2001:0db8:85a3:0000:0000:8a2e:0370:7334 (nouveau format, 128 bits, quasi-illimité)
#
# Pourquoi IPv6?
#   - IPv4 addresses épuisées (trop d'appareils: téléphones, IoT, etc)
#   - Internet grandit trop vite
#   - Besoin de BEAUCOUP plus d'adresses


# PORT

# POURQUOI?
# =========
# Une IP = un ordinateur, mais...
# Un ordinateur peut faire PLUSIEURS choses à la fois!
# Exemple:
#   - Tu écoutes une vidéo YouTube (port 443)
#   - Tu reçois des emails (port 587)
#   - Tu joues à un jeu en ligne (port 27015)
# Tout ça en même temps!

# Le port permet de DISTINGUER ces services!
# C'est comme avoir plusieurs "portes" sur une maison:
#   - Porte d'entrée = port 80
#   - Porte du garage = port 8080
#   - Porte arrière = port 3000

# QUAND?
# ======
# Chaque fois que tu crées une app:
#   - Flask: app.run(port=5000)
#   - FastAPI: uvicorn app:app --port 8000
#   - WebServer: écoute sur port 80 ou 443

# COMMENT?
# ========
# Les ports vont de 0 à 65535

# Ports spéciaux réservés:
#   80     = HTTP (web non sécurisé)
#   443    = HTTPS (web sécurisé)
#   22     = SSH (accès à distance sécurisé)
#   3306   = MySQL (base de données)
#   5432   = PostgreSQL (base de données)
#   25/587 = SMTP (envoyer des emails)
#   21     = FTP (transfer de fichiers)
#   53     = DNS (convertir noms en IPs)

# Ports pour développement (tu peux utiliser ce que tu veux):
#   3000, 5000, 8000, 8080, 8888, 9000

# Exemple: ta machine avec plusieurs services
#   IP: 192.168.1.100
#   └─ Port 5000: Flask app (ta super app web)
#   └─ Port 3306: MySQL (ta base de données)
#   └─ Port 6379: Redis (ton cache)

# Comment accéder?
#   API Flask: http://192.168.1.100:5000
#   Base de données: 192.168.1.100:3306
#   Cache Redis: 192.168.1.100:6379


# PROTOCOLE

# POURQUOI?
# =========
# Imagine deux personnes qui ne parlent pas la même langue
# L'une parle français, l'autre parle japonais
# Résultat: Impossibilité de communiquer!

# Les ordinateurs c'est pareil!
# Si deux ordinateurs n'utilisent pas le MÊME protocole:
#   - Ils ne se comprennent pas
#   - Les données sont invalides
#   - Erreur!

# Le protocole = un ensemble de RÈGLES communes
# "Voici comment on échange les données, tous d'accord?"

# QUAND?
# ======
# À chaque fois que deux ordinateurs communiquent, ils utilisent un protocole:
#   - Navigateur <-> Serveur web = HTTP
#   - PC <-> Routeur = TCP
#   - Videophone <-> Internet = UDP

# COMMENT?
# ========
# Protocoles principaux pour un développeur:

# HTTP = HyperText Transfer Protocol
#   - Utilisé pour: pages web, APIs
#   - Non sécurisé (tout le monde peut lire)
#   - Port: 80
#   - Exemple: GET http://example.com

# HTTPS = HTTP Secure (HTTP + chiffrement)
#   - Utilisé pour: pages web sécurisées, APIs bancaires
#   - Sécurisé (chiffré, personne ne peut lire)
#   - Port: 443
#   - Exemple: GET https://bank.example.com

# TCP = Transmission Control Protocol
#   - Utilisé pour: HTTP, HTTPS, SSH, bases de données
#   - FIABLE: les données arrivent dans le bon ordre
#   - Peut être lent (cause des vérifications)
#   - Exemple: connexion à une DB PostgreSQL

# UDP = User Datagram Protocol
#   - Utilisé pour: vidéos en streaming, jeux, voix
#   - RAPIDE mais PAS fiable (certaines données peuvent être perdues)
#   - Exemple: appel vidéo Zoom

# WebSocket = Communication bidirectionnelle temps réel
#   - Utilisé pour: chat, notifications, jeux multijoueurs
#   - Client ET serveur peuvent envoyer des données n'importe quand
#   - Exemple: chat en direct sur Facebook


# LOCALHOST (127.0.0.1)

# POURQUOI?
# =========
# Tu développes une app chez toi
# Tu veux la tester AVANT de la mettre en ligne
# Comment la tester sans la mettre accessible à tout Internet?

# RÉPONSE: localhost = l'adresse de TON ORDINATEUR

# QUAND?
# ======
# À CHAQUE FOIS que tu développes localement:
#   - Flask app sur ton ordi: python app.py
#   - Frontend React sur ton ordi: npm start
#   - Base de données sur ton ordi: localhost:5432

# COMMENT?
# ========
# localhost = 127.0.0.1 (c'est LA MÊME CHOSE)

# localhost:5000 = mon ordi, port 5000
#   - Accessible SEULEMENT de mon ordi
#   - Ton copain ne peut pas y accéder (même pas si tu lui donnes l'adresse!)
#   - Les données ne sortent pas d'Internet

# Exemple:
#   $ python app.py
#   Running on http://127.0.0.1:5000
#   
#   Tu ouvres ton navigateur et tapes: http://localhost:5000
#   Ça marche!
#   
#   Ton ami essaie: http://localhost:5000
#   Erreur! (car localhost c'est SON ordinateur à lui, pas le tien)

# Pour que ton ami accède à ton app en développement:
#   - Faut utiliser 0.0.0.0 à la place
#   - Ou mettre l'IP de ta machine (192.168.1.100)
#   - Et qu'il soit sur le même WiFi


# LOCALHOST vs 0.0.0.0

# POURQUOI?
# =========
# 127.0.0.1 = seulement TOI
# 0.0.0.0 = toi + tout Internet (si le port est exposé)

# C'est une question de SÉCURITÉ et d'ACCESSIBILITÉ

# QUAND?
# ======
# 127.0.0.1 en développement:
#   - Tu veux tester tout seul
#   - Tu ne veux pas que d'autres accèdent
#   - C'est plus sûr

# 0.0.0.0 en développement:
#   - Tu veux que ton copain en WiFi accède
#   - Tu fais un test avec plusieurs appareils

# En production (sur un serveur):
#   - TOUJOURS 0.0.0.0 (sinon personne d'Internet ne peut accéder!)

# COMMENT?
# ========
# Flask:
app.run(host='127.0.0.1')  # Seulement toi
app.run(host='0.0.0.0')    # Toi + Internet

# FastAPI / Uvicorn:
# $ uvicorn app:app --host 127.0.0.1  # Seulement toi
# $ uvicorn app:app --host 0.0.0.0    # Toi + Internet


# SERVEUR vs CLIENT

# POURQUOI?
# =========
# Dans une conversation téléphonique:
#   - Quelqu'un APPELLE (client)
#   - Quelqu'un REÇOIT (serveur)

# Les réseaux fonctionnent pareil!
# Il faut une DISTINCTION pour que ça marche

# QUAND?
# ======
# À CHAQUE FOIS qu'il y a communication:
#   - Navigateur <-> Site web = Client <-> Server
#   - App mobile <-> API = Client <-> Server
#   - PC <-> Imprimante = Client <-> Server

# COMMENT?
# ========

# SERVEUR:
#   - Attends les requêtes (toujours actif)
#   - Reçoit une demande
#   - Traite la demande
#   - Envoie une réponse
#   - Écoute sur un port spécifique
#   
# Exemple serveur Flask:
#   app.run(host='0.0.0.0', port=5000)
#   └─ Maintenant ça écoute: "Quelqu'un va venir me demander quelque chose?"

# CLIENT:
#   - Initie la communication
#   - Envoie une requête
#   - Attend une réponse
#   - Traite la réponse
#   - Se déconnecte
#   
# Exemple client (navigateur web):
#   Tu tapes: http://google.com
#   └─ Le navigateur demande: "Envoie-moi ta page d'accueil"
#   └─ Google répond: "Voici le HTML"
#   └─ Le navigateur affiche


# REQUÊTE vs RÉPONSE

# POURQUOI?
# =========
# La communication n'est pas magique!
# Il faut une STRUCTURE:
#   - Client dit quoi (requête)
#   - Serveur comprend quoi (requête)
#   - Serveur répond (réponse)
#   - Client reçoit (réponse)

# QUAND?
# ======
# À CHAQUE interaction entre client et serveur

# COMMENT?
# ========

# REQUÊTE (Client -> Serveur):
#   "Donne-moi la page d'accueil"
#
#   Contient:
#     - Méthode: GET (j'ai besoin de données)
#     - URL: /
#     - Protocole: HTTP/1.1
#     - Headers: info supplémentaires (navigateur utilisé, langues acceptées, etc)
#     - Body: données optionnelles (pour POST/PUT)
#
# Exemple complet:
#   GET / HTTP/1.1
#   Host: google.com
#   User-Agent: Mozilla/5.0
#   Accept-Language: fr-FR

# RÉPONSE (Serveur -> Client):
#   "Voici ta page d'accueil"
#
#   Contient:
#     - Code de statut: 200 (succès!)
#     - Headers: info sur la réponse (type de contenu, date, etc)
#     - Body: le contenu réel (HTML, JSON, fichier, etc)
#
# Exemple complet:
#   HTTP/1.1 200 OK
#   Content-Type: text/html
#   Content-Length: 1234
#   
#   <html>
#   <head><title>Google</title></head>
#   <body>...</body>
#   </html>


[OK] HTTP ET HTTPS EXPLIQUÉS TRÈS SIMPLEMENT

# === QU'EST-CE QUE HTTP? ===

# POURQUOI HTTP?
# ==============
# Avant HTTP, Internet n'existait pas vraiment!
# Les ordinateurs communiquaient de façons différentes (chaos!)

# HTTP = standardisation! Un protocole commun pour tous
# "Voici les règles: si tout le monde les suit, tout le monde se comprend"

# Avantages HTTP:
#   - Simple (pas compliqué)
#   - Universal (tout le monde l'utilise)
#   - Stateless (chaque requête est indépendante)
#   - Text-based (facile à lire et déboguer)

# QUAND UTILISER HTTP?
# ====================
# HTTP = pas sécurisé, mais simple
#
# Quand l'utiliser:
#   - Sites de test local
#   - Données NON sensibles
#   - Développement
#
# JAMAIS pour:
#   - Données sensibles (passwords, numéros de carte)
#   - Transactions bancaires
#   - Données personnelles
#   - Production réelle

# COMMENT HTTP FONCTIONNE?
# =========================

# 1. Client envoie une REQUÊTE HTTP
#    GET /users HTTP/1.1
#    Host: api.example.com

# 2. Internet transporte la requête

# 3. Serveur REÇOIT et TRAITE
#    "Quelqu'un demande /users"
#    Va chercher les utilisateurs en base de données

# 4. Serveur envoie une RÉPONSE HTTP
#    HTTP/1.1 200 OK
#    Content-Type: application/json
#    
#    [{'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}]

# 5. Internet transporte la réponse

# 6. Client REÇOIT et TRAITE
#    "Voici les utilisateurs!"
#    Affiche dans mon navigateur


# === MÉTHODES HTTP (TRÈS IMPORTANTES!) ===

# POURQUOI DIFFÉRENTES MÉTHODES?
# ===============================
# Imagine une bibliothèque:
#   - "Donne-moi ce livre" = GET (lis, ne change rien)
#   - "Ajoute ce livre" = POST (change la collection)
#   - "Remplace ce livre par celui-ci" = PUT (change complètement)
#   - "Change le titre de ce livre" = PATCH (change partiellement)
#   - "Enlève ce livre" = DELETE (enlève)

# Les méthodes HTTP = les actions possibles

# QUAND UTILISER CHAQUE MÉTHODE?
# ===============================

# GET = Récupérer des données
#   POURQUOI? "J'ai besoin de lire des données"
#   QUAND? Chercher un utilisateur, afficher une page web
#   COMMENT?
#     GET /users/123 HTTP/1.1
#     
#     Réponse:
#     200 OK
#     {'id': 123, 'name': 'Alice', 'email': 'alice@example.com'}
#   
#   Sûr? OUI (ne change rien)
#   Idempotent? OUI (plusieurs fois = même résultat)
#   Données dans l'URL? OUI (visible dans l'URL)

# POST = Créer une nouvelle ressource
#   POURQUOI? "Je veux ajouter quelque chose de NOUVEAU"
#   QUAND? Créer un user, créer un post, envoyer un formulaire
#   COMMENT?
#     POST /users HTTP/1.1
#     Content-Type: application/json
#     
#     {'name': 'Charlie', 'email': 'charlie@example.com'}
#     
#     Réponse:
#     201 Created
#     {'id': 124, 'name': 'Charlie', 'email': 'charlie@example.com'}
#   
#   Sûr? NON (crée une nouvelle ressource)
#   Idempotent? NON (deux fois = deux ressources créées)
#   Données dans l'URL? NON (dans le body = caché)

# PUT = Remplacer COMPLÈTEMENT une ressource
#   POURQUOI? "Je veux remplacer TOUTE la ressource"
#   QUAND? Remplacer un article complet
#   COMMENT?
#     PUT /users/123 HTTP/1.1
#     Content-Type: application/json
#     
#     {'id': 123, 'name': 'Alice Updated', 'email': 'alice.new@example.com', 'age': 30}
#     
#     Réponse:
#     200 OK
#     {'id': 123, 'name': 'Alice Updated', 'email': 'alice.new@example.com', 'age': 30}
#   
#   Important! PUT remplace TOUT
#   Si tu ne mets pas un champ: il est PERDU!
#   Sûr? NON (modifie la ressource)
#   Idempotent? OUI (plusieurs fois = même résultat)

# PATCH = Modifier PARTIELLEMENT une ressource
#   POURQUOI? "Je veux changer SEULEMENT certains champs"
#   QUAND? Changer l'email d'un user (garder tout le reste)
#   COMMENT?
#     PATCH /users/123 HTTP/1.1
#     Content-Type: application/json
#     
#     {'email': 'alice.newemail@example.com'}
#     
#     Réponse:
#     200 OK
#     {'id': 123, 'name': 'Alice Updated', 'email': 'alice.newemail@example.com', 'age': 30}
#   
#   Remarque! L'email a changé, tout le reste reste pareil!
#   Sûr? NON (modifie la ressource)
#   Idempotent? OUI (plusieurs fois = même résultat)

# DELETE = Supprimer une ressource
#   POURQUOI? "Je veux supprimer définitivement"
#   QUAND? Supprimer un user, supprimer un post
#   COMMENT?
#     DELETE /users/123 HTTP/1.1
#     
#     Réponse:
#     204 No Content
#     (pas de body, c'est supprimé!)
#   
#   ATTENTION! C'est définitif!
#   Sûr? NON (supprime la ressource)
#   Idempotent? OUI (plusieurs fois = supprimé, reste supprimé)


# === CODES DE STATUT HTTP (TRÈS IMPORTANTS!) ===

# POURQUOI DIFFÉRENTS CODES?
# ============================
# La réponse doit dire: "Ça a marché?" ET "Comment?"

# Client doit comprendre:
#   - C'est réussi? (2xx)
#   - Faut rediriger? (3xx)
#   - C'est ta faute? (4xx)
#   - C'est ma faute? (5xx)

# QUAND UTILISER CHAQUE CODE?
# ============================

# 2xx = Succès! Tout va bien!

#   200 OK
#   QUOI? La requête a réussi et voici le résultat
#   QUAND? La plupart du temps (GET, POST, PUT, PATCH)
#   EXEMPLE:
#     GET /users/123
#     Réponse: 200 OK
#     {'id': 123, 'name': 'Alice'}

#   201 Created
#   QUOI? La requête a réussi ET une nouvelle ressource a été créée
#   QUAND? POST (création)
#   EXEMPLE:
#     POST /users
#     Réponse: 201 Created
#     {'id': 124, 'name': 'Charlie'}

#   204 No Content
#   QUOI? La requête a réussi mais il n'y a rien à renvoyer
#   QUAND? DELETE, ou quand pas besoin de retourner de données
#   EXEMPLE:
#     DELETE /users/123
#     Réponse: 204 No Content
#     (rien!)

# 3xx = Redirection

#   301 Moved Permanently
#   QUOI? La ressource a déménagé définitivement à une autre URL
#   QUAND? Quand une URL change pour toujours
#   EXEMPLE:
#     GET /old-url
#     Réponse: 301 Moved Permanently
#     Location: /new-url
#     (le navigateur va automatiquement à /new-url)

#   302 Found
#   QUOI? La ressource a déménagé temporairement
#   QUAND? Quand une URL change provisoirement
#   EXEMPLE:
#     GET /users/123
#     Réponse: 302 Found
#     Location: /users/123/profile
#     (redirection temporaire)

#   304 Not Modified
#   QUOI? Les données n'ont pas changé depuis la dernière fois
#   QUAND? Caching (éviter de retransmetter les mêmes données)
#   EXEMPLE:
#     GET /data (avec header "If-Modified-Since: date")
#     Réponse: 304 Not Modified
#     (pas besoin de retransmettre, utilise le cache!)

# 4xx = Erreur du CLIENT

#   400 Bad Request
#   QUOI? La requête est mal formée
#   QUAND? Données invalides, format mauvais
#   EXEMPLE:
#     POST /users
#     {'name': null, 'email': 'invalid'}
#     Réponse: 400 Bad Request
#     (erreur: data invalide)

#   401 Unauthorized
#   QUOI? Pas authentifié (tu dois te connecter)
#   QUAND? Pas de login, pas de token JWT
#   EXEMPLE:
#     GET /protected-data (sans token)
#     Réponse: 401 Unauthorized
#     (besoin de token!)

#   403 Forbidden
#   QUOI? Authentifié mais pas d'accès (tu as pas les permissions)
#   QUAND? Utilisateur existe mais n'a pas les droits
#   EXEMPLE:
#     GET /admin-panel (avec user normal, pas admin)
#     Réponse: 403 Forbidden
#     (tu as pas les droits!)

#   404 Not Found
#   QUOI? La ressource n'existe pas
#   QUAND? URL inexistant, ID n'existe pas
#   EXEMPLE:
#     GET /users/9999 (user 9999 n'existe pas)
#     Réponse: 404 Not Found
#     (utilisateur introuvable)

# 5xx = Erreur du SERVEUR

#   500 Internal Server Error
#   QUOI? Une erreur s'est produite sur le serveur
#   QUAND? Bug du code serveur
#   EXEMPLE:
#     GET /users
#     (division par zéro dans le code!)
#     Réponse: 500 Internal Server Error
#     (bug du serveur)

#   502 Bad Gateway
#   QUOI? Le serveur intermédiaire (reverse proxy) ne peut pas atteindre le vrai serveur
#   QUAND? Nginx <-> Flask: Flask n'est pas actif
#   EXEMPLE:
#     GET / (Nginx est actif mais Flask est down)
#     Réponse: 502 Bad Gateway
#     (Flask n'est pas accessible)

#   503 Service Unavailable
#   QUOI? Le serveur est surchargé ou en maintenance
#   QUAND? Trop de requêtes, redémarrage du serveur
#   EXEMPLE:
#     GET / (serveur en maint)
#     Réponse: 503 Service Unavailable
#     (reviens plus tard)


# === HTTPS = HTTP SÉCURISÉ ===

# POURQUOI HTTPS?
# ===============
# Imagine tu envoies une carte postale par la poste
# Tout le monde peut la lire en chemin!
# Pareil pour HTTP: tout le monde peut lire tes données!

# Problème:
#   - Tu tappe un password dans un formulaire
#   - HTTP l'envoie en TEXTE CLAIR
#   - N'importe qui qui "écoute" le réseau peut voir
#   - DANGER!

# HTTPS = HTTP + SSL/TLS (Secure Sockets Layer / Transport Layer Security)
# = HTTP mais les données sont CHIFFRÉES

# Analogie: HTTPS = envoyer une lettre dans un coffre-fort
#   - Coffre fermé avec serrure
#   - Seul destinataire peut l'ouvrir
#   - Personne ne peut lire le contenu en chemin

# QUAND UTILISER HTTPS?
# ======================
# TOUJOURS en production!
# Règle d'or: "Si ça touche Internet, utilise HTTPS"

# Exceptions OK pour HTTP:
#   - Développement local (127.0.0.1)
#   - Réseau privé fermé
#   - Données 100% publiques et non sensibles

# COMMENT HTTPS FONCTIONNE?
# ==========================

# 1. Client (navigateur) se connecte au serveur (HTTPS port 443)

# 2. Handshake SSL/TLS:
#    - Serveur envoie son certificat
#    - Client vérifie le certificat (est-ce vraiment Google?)
#    - Ils échangent des clés de chiffrement

# 3. Tout ce qui est envoyé = CHIFFRÉ
#    - Client envoie: "password: alice123" (CHIFFRÉ)
#    - Seul serveur peut déchiffrer
#    - Les "écouteurs" réseau voient: [données aléatoires chiffrées]

# 4. Réponse = CHIFFRÉ aussi
#    - Serveur envoie: "Connecté!" (CHIFFRÉ)
#    - Seul client peut déchiffrer

# CERTIFICAT SSL/TLS:
# ====================
# POURQUOI?
# = Preuve d'identité numérique
# = "Je suis vraiment Google, pas une arnaque"
# = Sinon, un hacker pourrait faire un FAUX Google et tu enverrais tes données!

# QUAND?
# = Chaque HTTPS utilise un certificat
# = Tu vois "[VERROUILLE]" dans le navigateur? C'est grâce au certificat

# COMMENT?
# Certificat contient:
#   - Domaine (google.com)
#   - Clé publique (pour chiffrer)
#   - Signature d'une autorité de confiance (Let's Encrypt, GlobalSign, etc)
#   - Date d'expiration (certificats expirent!)

# En Python avec Flask:
from flask import Flask
import ssl

app = Flask(__name__)

if __name__ == '__main__':
    # Créer un contexte SSL
    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    # Charger le certificat et la clé
    ssl_context.load_cert_chain('cert.pem', 'key.pem')
    # Lancer en HTTPS
    app.run(host='0.0.0.0', port=443, ssl_context=ssl_context)

# Maintenant l'app est accessible via: https://localhost


[OK] TCP ET UDP EXPLIQUÉS EN DÉTAIL

# === TCP (TRANSMISSION CONTROL PROTOCOL) ===

# POURQUOI TCP?
# =============
# Imagine tu commandes un gâteau par internet
# Si le gâteau arrive en miettes, c'est PAS BON!
# TCP = garantit que le gâteau arrive ENTIER et dans le BON ORDRE

# TCP = "Je garantis que tes données arrivent correctement"

# Problèmes que TCP résout:
#   1. Perte de données en chemin
#   2. Données en mauvais ordre
#   3. Pas de confirmation d'arrivée

# QUAND UTILISER TCP?
# ===================
# Quand la FIABILITÉ est plus importante que la VITESSE

# Utilise TCP pour:
#   - Communication web (HTTP/HTTPS) <- les pages web DOIVENT arriver
#   - Email (SMTP) <- tes emails DOIVENT arriver
#   - SSH (connexion à serveur) <- les commandes DOIVENT arriver exactement
#   - Bases de données <- les données DOIVENT être correctes
#   - Transfert de fichiers (FTP) <- les fichiers DOIVENT être complets

# COMMENT TCP FONCTIONNE?
# ========================

# 1. CLIENT initie la connexion (3-way handshake)
#    Client: "Yo serveur, tu m'écoutes?" (SYN)
#    Serveur: "Oui je t'écoute, tu me reçois?" (SYN-ACK)
#    Client: "Oui je te reçois!" (ACK)
#    └─ Connexion établie! [OK]

# 2. Envoi des données avec vérification
#    Client: "Voici 100 bytes de données" (avec numéro de séquence)
#    Serveur: "J'ai bien reçu les 100 bytes" (ACK)
#    Client: "Voici les 100 bytes suivants"
#    Serveur: "J'ai bien reçu"
#    └─ Chaque chunk est confirmé

# 3. Fermeture de la connexion
#    Client: "J'ai fini" (FIN)
#    Serveur: "OK" (FIN-ACK)
#    └─ Connexion fermée proprement

# AVANTAGES TCP:
#   [OK] Fiable
#   [OK] Ordonné
#   [OK] Contrôle d'erreurs
#   [OK] Re-transmission automatique

# INCONVÉNIENTS TCP:
#   [X] Plus lent
#   [X] Overhead (beaucoup d'informations de contrôle)
#   [X] Connexion persistante (ressources utilisées)


# === UDP (USER DATAGRAM PROTOCOL) ===

# POURQUOI UDP?
# =============
# Imagine tu regardes YouTube
# Si une frame vidéo se perd, c'est pas grave! (tu vois pas vraiment)
# UDP = "Envoie les données super vite, les contrôles c'est chiant"

# UDP = "Je m'en fous de la fiabilité, la VITESSE c'est tout!"

# QUAND UTILISER UDP?
# ===================
# Quand la VITESSE est plus importante que la FIABILITÉ

# Utilise UDP pour:
#   - Streaming vidéo (YouTube, Twitch) <- perdre une frame c'est OK
#   - Jeux en ligne <- perdre un paquet c'est OK, t'es pas mort
#   - Appels vidéo (Zoom, Skype) <- perdre un son = juste "glitch" pas grave
#   - DNS <- si une requête se perd, on relance simplement
#   - IoT (capteurs) <- données en continu, une donnée perdue c'est OK

# COMMENT UDP FONCTIONNE?
# ========================

# 1. CLIENT envoie juste les données
#    Client: "Voici 1000 bytes de données!" (yolo!)
#    └─ Pas de handshake, pas d'attente

# 2. SERVEUR reçoit (ou pas!)
#    Serveur: "J'ai reçu 1000 bytes" (peut-être)
#    └─ Pas de confirmation obligatoire

# 3. Pas de fermeture propre
#    Client s'arrête simplement
#    └─ Done!

# AVANTAGES UDP:
#   [OK] Super rapide
#   [OK] Léger
#   [OK] Pas d'overhead
#   [OK] Multicast possible

# INCONVÉNIENTS UDP:
#   [X] Données peuvent se perdre
#   [X] Données peuvent arriver en désordre
#   [X] Pas de retransmission automatique
#   [X] Moins de garanties


# === COMPARAISON TCP vs UDP ===

# TCP:
#   Fiabilité:      ***** (100% fiable)
#   Vitesse:        ***** (plus lent)
#   Connexion:      Persistante (établie puis fermée)
#   Ordre:          Garanti (dans le même ordre envoyé)
#   Perte:          Retransmise automatiquement
#   Overhead:       Élevé (beaucoup de vérification)

# UDP:
#   Fiabilité:      ***** (pas fiable)
#   Vitesse:        ***** (très rapide)
#   Connexion:      Sans état (envoie et oublie)
#   Ordre:          Pas garanti (peut arriver en désordre)
#   Perte:          Perdue (pas de retransmission)
#   Overhead:       Faible (juste envoyer)

# Tableau comparatif:
# ┌─────────────────┬──────────────────┬──────────────────┐
# │ Critère         │ TCP              │ UDP              │
# ├─────────────────┼──────────────────┼──────────────────┤
# │ Fiabilité       │ Garantie         │ Non garantie     │
# │ Vitesse         │ Lent             │ Rapide           │
# │ Connection      │ Établie/Fermée   │ Aucune           │
# │ Ordre           │ Garanti          │ Non garanti      │
# │ Exemple         │ HTTP, Email      │ Video, Jeux      │
# └─────────────────┴──────────────────┴──────────────────┘


[OK] SOCKETS EXPLIQUÉES AVEC DÉTAILS

# === QU'EST-CE QU'UNE SOCKET? ===

# POURQUOI?
# =========
# Les données doivent voyager dans un "tuyau"
# Ce tuyau = socket
# C'est l'interface entre ton application et le réseau

# Analogie: Socket = prise téléphonique à ta maison
#   - Avant: t'étais câblé directement au système téléphonique (chaotique!)
#   - Maintenant: tu branches ton téléphone dans la prise (clean!)
#   - La prise = socket

# QUAND?
# ======
# À chaque fois que tu fais de la communication réseau:
#   - Navigateur <-> Serveur web
#   - App Python <-> Base de données
#   - Chat <-> Chat

# COMMENT?
# ========

# Deux types de sockets:

# 1. SERVER SOCKET (L'ÉCOUTEUR)
#    └─ Attend les connexions
#    └─ Comme le standard d'un hôtel: "Allô? Bienvenue!"

# 2. CLIENT SOCKET (LE DEMANDEUR)
#    └─ Se connecte à un serveur
#    └─ Comme toi qui appelles l'hôtel: "Yo, c'est moi!"


# === EXEMPLE DÉTAILLÉ: SERVER SOCKET EN PYTHON ===

import socket
import threading

# ÉTAPE 1: Créer une socket serveur
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#                            ^                 ^
#                            IPv4          TCP (fiable)

# POURQUOI AF_INET?
# = Address Family: INET = Internet (IPv4)
# = Il y a aussi AF_INET6 pour IPv6

# POURQUOI SOCK_STREAM?
# = STREAM = flux continu de données
# = Il y a aussi SOCK_DGRAM pour UDP

# ÉTAPE 2: Bind (attacher la socket à une adresse et port)
server_socket.bind(('0.0.0.0', 5000))
#                   ^            ^
#                   IP        Port
# 0.0.0.0 = écouter sur TOUTES les interfaces réseau

# POURQUOI bind?
# = Dire au système d'exploitation: "Écoute sur ce port s'il te plaît"
# = Sans bind, personne ne sait où chercher

# ÉTAPE 3: Listen (attendre les connexions)
server_socket.listen(5)
#                     ^
#                     Max 5 connexions en attente

# POURQUOI listen?
# = "Je suis prêt à recevoir des connexions"
# = Le 5 = file d'attente (si 6 gens arrivent en même temps, 1 attend)

print("Serveur écoute sur 0.0.0.0:5000...")

# ÉTAPE 4: Accept (accepter une connexion)
client_socket, client_address = server_socket.accept()
#                              ^                 ^
#                       New connection      Client's IP:Port

# POURQUOI accept?
# = Se bloquer jusqu'à ce qu'un client arrive
# = Une fois un client arrive, créer une NEW socket pour communiquer

print(f"Client connecté de: {client_address}")
# Affiche: Client connecté de: ('192.168.1.100', 54321)

# ÉTAPE 5: Recevoir des données
data = client_socket.recv(1024)
#                          ^
#                    Max bytes à recevoir

# POURQUOI recv(1024)?
# = 1024 bytes = 1 KB (taille du buffer)
# = Si le message est plus gros: faut appeler recv plusieurs fois

print(f"Message reçu: {data.decode()}")

# ÉTAPE 6: Envoyer une réponse
response = "Salut du serveur!"
client_socket.send(response.encode())

# POURQUOI encode()?
# = Les sockets envoient des BYTES, pas des strings
# = "Salut" (string) -> encode() -> b'Salut' (bytes)

# ÉTAPE 7: Fermer la connexion
client_socket.close()
server_socket.close()

# POURQUOI close?
# = Libérer les ressources (la socket tient de la RAM!)
# = Sans close: fuite mémoire


# === EXEMPLE DÉTAILLÉ: CLIENT SOCKET EN PYTHON ===

import socket

# ÉTAPE 1: Créer une socket client
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# ÉTAPE 2: Se connecter à un serveur (CONNECT)
client_socket.connect(('localhost', 5000))
#                      ^               ^
#                      Serveur      Port

# POURQUOI connect?
# = Établir la connexion TCP
# = Si le serveur n'écoute pas: ConnectionRefusedError!

print("Connecté au serveur!")

# ÉTAPE 3: Envoyer des données
message = "Bonjour serveur!"
client_socket.send(message.encode())

# ÉTAPE 4: Recevoir une réponse
response = client_socket.recv(1024)
print(f"Réponse du serveur: {response.decode()}")

# ÉTAPE 5: Fermer la connexion
client_socket.close()


# === FLUX COMPLET: Qu'est-ce qui se passe? ===

# SERVEUR:
#   1. Crée une socket
#   2. Bind à 0.0.0.0:5000
#   3. Listen (attend)
#   4. Bloque sur accept() <- attend ici!

# CLIENT:
#   1. Crée une socket
#   2. Connect à localhost:5000
#   └─ Envoie SYN
#   └─ Attend SYN-ACK

# SERVEUR (TCP handshake):
#   <- Reçoit SYN
#   -> Envoie SYN-ACK
#   <- Reçoit ACK
#   └─ Accept retourne!

# CLIENT:
#   -> Envoie "Bonjour serveur!"

# SERVEUR:
#   <- Recv reçoit le message
#   -> Envoie "Salut du serveur!"

# CLIENT:
#   <- Recv reçoit la réponse
#   -> Close la socket

# SERVEUR:
#   <- Reçoit FIN
#   -> Envoie FIN-ACK
#   -> Close la socket


[OK] APPLICATIONS WEB: FLASK ET FASTAPI EN DÉTAIL

# === FLASK: FRAMEWORK WEB SIMPLE ===

# POURQUOI FLASK?
# ===============
# Les sockets bas-niveau c'est compliqué!
# 100 lignes juste pour dire "Bonjour"?

# Flask = une COUCHE D'ABSTRACTION
# = "Fais les sockets à ma place, je veux juste coder mon app"

# QUAND UTILISER FLASK?
# =====================
# Utilise Flask pour:
#   - Prototypes rapides
#   - Petites/moyennes apps
#   - APIs simples
#   - Apprendre

# Utilise autre chose si:
#   - Ultra haute performance (FastAPI)
#   - Très complexe (Django)
#   - Cas spécifique

# COMMENT FLASK FONCTIONNE?
# ==========================

from flask import Flask, request, jsonify

app = Flask(__name__)

# STEP 1: Créer l'app
# __name__ = module courant = "run ce code ici"

# STEP 2: Définir les routes (les URLs)

@app.route('/')
def home():
    # QUAND? Quelqu'un accède à http://localhost:5000/
    # POURQUOI? Flask appelle cette fonction
    # COMMENT? Retourner ce qu'on veut afficher
    return "Bienvenue!"

# Derrière les scènes, Flask:
#   1. Crée une socket serveur sur 0.0.0.0:5000
#   2. Écoute les requêtes HTTP
#   3. Parse la requête (extrait l'URL, la méthode, les headers)
#   4. Regarde les routes: "Quelle fonction correspond à cette URL?"
#   5. Appelle la fonction
#   6. Retourne la réponse HTTP

@app.route('/users', methods=['GET'])
def get_users():
    # GET /users
    # QUOI? Récupérer tous les utilisateurs
    users = [
        {'id': 1, 'name': 'Alice'},
        {'id': 2, 'name': 'Bob'}
    ]
    return jsonify(users)
    # jsonify() = convertir Python list -> JSON string

@app.route('/users', methods=['POST'])
def create_user():
    # POST /users avec body JSON
    # QUOI? Créer un nouvel utilisateur
    
    data = request.get_json()
    # data = {'name': 'Charlie', 'email': 'charlie@example.com'}
    # request = objet Flask contenant la requête complète
    
    new_user = {
        'id': 3,
        'name': data['name'],
        'email': data['email']
    }
    
    return jsonify(new_user), 201
    # 201 = Created (nouvel utilisateur créé!)

@app.route('/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
    # GET /users/123
    # <int:user_id> = extraire 123 de l'URL
    
    # Chercher l'utilisateur
    if user_id == 1:
        return jsonify({'id': 1, 'name': 'Alice'})
    else:
        return {'error': 'Not found'}, 404

@app.route('/users/<int:user_id>', methods=['PUT'])
def update_user(user_id):
    # PUT /users/123
    # Remplacer complètement
    
    data = request.get_json()
    return jsonify({'id': user_id, 'name': data['name']}), 200

@app.route('/users/<int:user_id>', methods=['PATCH'])
def patch_user(user_id):
    # PATCH /users/123
    # Modifier partiellement
    
    data = request.get_json()
    return jsonify({'id': user_id, 'updated': True}), 200

@app.route('/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
    # DELETE /users/123
    # Supprimer
    
    return '', 204
    # 204 = No Content (rien à retourner)

if __name__ == '__main__':
    # POURQUOI if __name__ == '__main__'?
    # = Ne lancer que si ce fichier est exécuté directement
    # = Si importé d'ailleurs, pas de lancement automatique
    
    app.run(
        host='0.0.0.0',      # Accessible d'Internet
        port=5000,           # Port d'écoute
        debug=False          # debug=False en prod! (sinon risque de sécurité)
    )

# Commande pour lancer:
# $ python app.py
# * Running on http://0.0.0.0:5000
# Maintenant tu peux taper http://localhost:5000 dans ton navigateur!


# === FASTAPI: FRAMEWORK WEB MODERNE ===

# POURQUOI FASTAPI?
# =================
# FastAPI = Flask mais en 2024!
#   - Plus rapide (AsyncIO)
#   - Meilleure validation (Pydantic)
#   - Documentation auto (Swagger)
#   - Type hints

# QUAND UTILISER FASTAPI?
# =======================
# Utilise FastAPI pour:
#   - Performance critique
#   - APIs modernes
#   - Apps haute concurrence
#   - Si tu aimes la type safety

# COMMENT FASTAPI FONCTIONNE?
# ============================

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

# Modèle de données (validation automatique!)
class User(BaseModel):
    name: str
    email: str

# POURQUOI BaseModel?
# = Valider automatiquement les données
# = Si quelqu'un envoie {'name': null}: FastAPI rejette
# = Si quelqu'un envoie du mauvais JSON: erreur 400

@app.get('/')
def read_root():
    # GET /
    return {'message': 'Bienvenue à FastAPI!'}

@app.get('/users')
def get_users():
    # GET /users
    return [
        {'id': 1, 'name': 'Alice'},
        {'id': 2, 'name': 'Bob'}
    ]

@app.post('/users')
def create_user(user: User):
    # POST /users
    # user: User = validation auto!
    # Si data invalide: FastAPI retourne 422 Unprocessable Entity
    
    new_user = {
        'id': 3,
        'name': user.name,
        'email': user.email
    }
    return new_user

@app.get('/users/{user_id}')
def get_user(user_id: int):
    # GET /users/123
    # user_id: int = conversion automatique de string -> int
    
    if user_id == 1:
        return {'id': 1, 'name': 'Alice'}
    raise HTTPException(status_code=404, detail="User not found")
    # HTTPException = retourner une erreur HTTP proprement

@app.put('/users/{user_id}')
def update_user(user_id: int, user: User):
    # PUT /users/123
    return {'id': user_id, 'name': user.name}

@app.delete('/users/{user_id}')
def delete_user(user_id: int):
    # DELETE /users/123
    return {'message': 'User deleted'}

# Lancer FastAPI:
# $ pip install fastapi uvicorn
# $ uvicorn app:app --reload --host 0.0.0.0 --port 8000
# 
# Automatiquement:
#   - Documentation Swagger: http://localhost:8000/docs
#   - ReDoc: http://localhost:8000/redoc

# AVANTAGES FASTAPI:
#   [OK] Validation auto
#   [OK] Doc auto
#   [OK] Async/await
#   [OK] Type hints
#   [OK] Plus rapide que Flask

# INCONVÉNIENTS FASTAPI:
#   [X] Écosystème plus petit que Flask
#   [X] Courbe d'apprentissage (async)


[OK] WEBSOCKET: COMMUNICATION TEMPS RÉEL EN DÉTAIL

# === QU'EST-CE QUE WEBSOCKET? ===

# POURQUOI WEBSOCKET?
# ===================
# Imagine un chat Facebook:
#   - Ami envoie un message
#   - Comment TU le reçois?

# Avec HTTP normal:
#   - Tu demandes "Y a des nouveaux messages?"
#   - Toutes les secondes tu demandes
#   - Super inefficace!

# AVEC WEBSOCKET:
#   - Tu établis une connexion persistante
#   - Ton ami envoie un message
#   - TOI tu le reçois IMMÉDIATEMENT
#   - Sans demander!

# WebSocket = communication BIDIRECTIONNELLE
# = Client ET Serveur peuvent envoyer n'importe quand

# QUAND UTILISER WEBSOCKET?
# ==========================
# Utilise WebSocket pour:
#   - Chat en temps réel
#   - Notifications push
#   - Jeux multijoueurs
#   - Tableaux de bord temps réel
#   - Collaboration live (Google Docs style)

# NE PAS utiliser WebSocket pour:
#   - Simple page web statique (HTTP suffit)
#   - Formulaires de contact (HTTP POST suffit)
#   - Si besoin d'une seule réponse (HTTP suffit)

# COMMENT WEBSOCKET FONCTIONNE?
# ==============================

# 1. Client établit une connexion HTTP d'abord
#    GET / HTTP/1.1
#    Upgrade: websocket
#    Connection: Upgrade
#    └─ Demande: "Peux-tu upgrader en WebSocket?"

# 2. Serveur accepte
#    HTTP/1.1 101 Switching Protocols
#    Upgrade: websocket
#    └─ Réponse: "OK, on switch!"

# 3. Maintenant = WebSocket connection (TCP bidirectionnelle)
#    Client peut envoyer n'importe quand
#    Serveur peut envoyer n'importe quand
#    Pas besoin de requête/réponse

# 4. Quand quelqu'un envoie un message:
#    Émetteur: emit('message', data)
#    └─ Tout le monde reçoit

# === WEBSOCKET AVEC FLASK-SOCKETIO ===

# POURQUOI SOCKETIO?
# ==================
# Flask n'a pas WebSocket natif
# Flask-SocketIO = extension Flask pour WebSocket
# = Facile à utiliser, pas besoin de coder bas niveau

# COMMENT?

from flask import Flask, render_template
from flask_socketio import SocketIO, emit, join_room, leave_room

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret-key-change-moi'
socketio = SocketIO(app)

# POURQUOI SECRET_KEY?
# = Pour signer les sessions
# = Protection contre les attaques

# Événements WebSocket:

@socketio.on('connect')
def handle_connect():
    # QUAND? Client établit la connexion WebSocket
    # POURQUOI? Accueillir le client
    # COMMENT? Appeler cette fonction
    
    print('Client connecté')
    emit('response', {'data': 'Tu es connecté au serveur!'})
    # emit() = envoyer un message à ce client

@socketio.on('disconnect')
def handle_disconnect():
    # QUAND? Client se déconnecte
    # POURQUOI? Nettoyer les ressources
    
    print('Client déconnecté')

@socketio.on('message')
def handle_message(data):
    # QUAND? Client envoie un message
    # POURQUOI? Traiter le message
    # COMMENT? data = ce que le client a envoyé
    
    print(f'Message reçu: {data}')
    # Envoyer à TOUS les clients connectés
    emit('response', {'data': data}, broadcast=True)
    # broadcast=True = tout le monde reçoit

@socketio.on('join_room')
def on_join(data):
    # QUAND? Client veut rejoindre une "room"
    # POURQUOI? Grouper les clients (chat rooms)
    
    room = data['room']
    username = data['username']
    
    join_room(room)
    # Maintenant ce client est dans une room
    # Les messages dans cette room = seulement pour cette room
    
    emit('message', 
         {'msg': f'{username} a rejoint'}, 
         room=room)
    # Envoyer à tous dans la room

@socketio.on('chat_message')
def handle_chat(data):
    # Chat dans une room
    room = data['room']
    message = data['message']
    username = data['username']
    
    emit('chat_response',
         {'username': username, 'message': message},
         room=room)
    # Seulement les gens dans la room reçoivent

if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=5000, debug=False)


# === CLIENT WEBSOCKET (JavaScript dans navigateur) ===

# <!DOCTYPE html>
# <html>
# <head>
#     <title>Chat WebSocket</title>
#     <script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
# </head>
# <body>
#     <h1>Chat en temps réel</h1>
#     <div id="messages"></div>
#     <input type="text" id="messageInput" placeholder="Message">
#     <button onclick="sendMessage()">Envoyer</button>

#     <script>
#         // Connecter au serveur WebSocket
#         const socket = io();
#         // socket = objet pour communiquer avec le serveur

#         // QUAND: Connection établie
#         socket.on('connect', function() {
#             console.log('Connecté au serveur!');
#         });

#         // QUAND: Recevoir un message
#         socket.on('response', function(data) {
#             console.log('Du serveur:', data.data);
#             document.getElementById('messages').innerHTML += data.data + '<br>';
#         });

#         // QUAND: User click "Envoyer"
#         function sendMessage() {
#             const msg = document.getElementById('messageInput').value;
#             // Envoyer au serveur
#             socket.emit('message', msg);
#             document.getElementById('messageInput').value = '';
#         }

#         // QUAND: Disconnect
#         socket.on('disconnect', function() {
#             console.log('Déconnecté');
#         });
#     </script>
# </body>
# </html>

# AVANTAGES WEBSOCKET:
#   [OK] Temps réel
#   [OK] Bidirectionnelle
#   [OK] Connexion persistante
#   [OK] Faible latence

# INCONVÉNIENTS WEBSOCKET:
#   [X] Plus complexe que HTTP
#   [X] Utilisuje plus de ressources serveur
#   [X] Pas bon pour données statiques
#   [X] Problèmes de firewall possibles


[OK] REQUÊTES HTTP EN PYTHON: REQUESTS ET HTTPX

# === LIBRARIE REQUESTS (CLIENT HTTP) ===

# POURQUOI REQUESTS?
# ==================
# Tu veux appeler une API depuis ton code Python
# Exemple: tu veux récupérer la météo de OpenWeatherMap
# Ou tu veux envoyer un message à une API

# requests = librarie pour faire des requêtes HTTP
# = Beaucoup plus simple que les sockets bas niveau

# QUAND UTILISER?
# ===============
# À CHAQUE FOIS que tu dois appeler une API externe:
#   - OpenWeatherMap (météo)
#   - Stripe (paiements)
#   - Twilio (SMS)
#   - GitHub API
#   - Toute API public

# COMMENT?
# ========

import requests

# GET request (récupérer des